import {ROUTE_PREFIX} from '../constants';
import 'reflect-metadata';

export const getArguments = (params, ctx, next): any[] => {
    let args = [ctx, next];
    if (params) {
        args = [];

        params.sort((a, b) => a.index - b.index);

        for (const param of params) {
            let result;
            if (param !== undefined) result = param.fn(ctx);
            args.push(result);
        }
    }
    return args;
};

class FileDownload {
    file: any;

    fileName: string;

    mimeType: string;

    constructor(_file: any, _fileName: string, _mimeType: string) {
        // old school assignment until tswag supports constructor documentation
        this.file = _file;
        this.fileName = _fileName;
        this.mimeType = _mimeType;
    }
}

export function bindRoutes(routerRoutes: any, controllers: any[], getter?: (ctrl) => any): any {
    for (const ctrl of controllers) {
        const routes = Reflect.getMetadata(ROUTE_PREFIX, ctrl);

        for (const {method, url, middleware, name, params} of routes) {
            routerRoutes[method](url, ...middleware, async function (ctx, next) {
                const inst = getter === undefined ?
                    new ctrl() : getter(ctrl);

                const args = getArguments(params, ctx, next);
                const result = inst[name](...args);
                if (result) {
                    const body = await result;
                    if (body instanceof FileDownload) {
                        const fileDownload = <FileDownload>body;
                        ctx.res.setHeader('Content-type', fileDownload.mimeType);
                        ctx.res.setHeader('Content-disposition', ('attachment; filename=' + fileDownload.fileName));
                        ctx.attachment(fileDownload.fileName);
                        ctx.body = fileDownload.file;
                    } else {
                        ctx.body = body;
                    }
                }
                return result;
            });
        }
    }

    return routerRoutes;
}
